#include "widget_manager.h"
#include "ui_widget_manager.h"

// add necessaray includes here
#include "can/can_bll_t1c.h"
#include "log/log_bll.h"
#include "utils/configure/configure_bll.h"
#include "utils/keyboard/keyboard_mgr.h"
#include "utils/upgrade/upgrade_bll.h"
#include "utils/firmware/firmware_bll.h"

#include "ui/home/form_status_bar.h"
#include "ui/home/form_tool_bar.h"
#include "ui/home/homepage/form_home.h"
#include "ui/home/form_self_check.h"
#include "ui/home/form_login.h"

#include "ui/setting/form_setting.h"
#include "ui/setting/form_setting_mode.h"
#include "ui/setting/form_setting_language.h"
#include "ui/setting/form_setting_rtc.h"
#include "ui/setting/form_setting_network.h"
#include "ui/setting/form_setting_log.h"
#include "ui/setting/form_setting_upgrade.h"
#include "ui/setting/form_setting_data_tools.h"
#include "ui/setting/form_setting_version.h"

#include "ui/factory/form_factory.h"
#include "ui/factory/uvc/form_uv_disinfection.h"
#include "ui/factory/heating_debug/form_heating_debug.h"
#include "ui/factory/motor_debug/form_motor_debug.h"
#include "ui/factory/process_debug/form_process_debug.h"
#include "ui/factory/extract_debug/form_extract_debug.h"
#include "ui/factory/factory_params/form_factory_params.h"
#include "ui/factory/self-checking/form_self_checking.h"
#include "ui/factory/device_notify/form_device_notify.h"

#include "ui/share/form_prompt_dlg.h"

//#define DF_IF_ICOM    "ISerialport"
#define DF_IF_ICAN      "ICan"
#ifdef QT_NO_DEBUG
#define DF_IF_ILOG      "ILog"
#endif

std::vector<QPluginLoader*> g_vecPluginLoader;
std::map<QString, QPluginLoader*> g_mapPluginLoader;

QMultiMap<EUM_TASK_TYPE, unsigned int> g_mapTestTaskRunning;
int g_nKitType;

#ifdef DF_IF_ILOG
void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    if(LogBLL::getInstance()) LogBLL::getInstance()->outputMessage(type, context, msg);
}
#endif

WidgetManager::WidgetManager(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::WidgetManager)
{
    ui->setupUi(this);

    // After constructing object, initialize the object
    _initialze();

    // Init the window style
    _initUi();
}

WidgetManager::~WidgetManager()
{
    delete ui;

#ifdef QT_NO_DEBUG
    _unloadPlugins();
#endif
}

/*
 * Function:    _initialze
 * Description: After constructing object, initialize the object
 * Paramer:     void
 * Return:      void
 */
void WidgetManager::_initialze()
{
    qDebug() << Q_FUNC_INFO;

    // Load plugins from local
#ifdef QT_NO_DEBUG
//    int nErrCode = _loadPlugins();
//    if(0 > nErrCode)  QMessageBox::warning(this, "Warn", QString("%1(%2)").arg("Plugins can't be loaded").arg(nErrCode), QMessageBox::Ok);
#endif

    // Configure language & CAN
    _configFromINI();

    // Initialize interfaces
    _initInterfaces();

    // Config firmware
    _configFirmware();

    // Load the QSS file for the common control
    _loadCommonQSS();

    // Get the window instances
    _getWindowInstance();

    // Correlation signal and slot function
    _associateSignalSlot();
}

/*
* Function:		_initUi
* Description:	Init the window style
* Paramer:		void
* Return:		void
*/
void WidgetManager::_initUi()
{
    qDebug() << Q_FUNC_INFO;

    // Hide the title bar
#ifdef QT_NO_DEBUG
//    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
#endif

    // Set the size of the mainframe
    setFixedSize(DEF_MAINFRAME_WIDTH, DEF_MAINFRAME_HEIGHT);
    setGeometry(0, 0, this->geometry().width(), this->geometry().height());

    // Config PWM device
    int nPwmResult = FirmwareBLL::getInstance(this)->configPWM();
    if(0 != nPwmResult) {
        qDebug() << Q_FUNC_INFO << "PWM configure failed" + QString(" [%1]").arg(nPwmResult);
    }

#ifdef QT_NO_DEBUG
    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    m_pFrmSelfCheck->show();
    m_pFrmSelfCheck->signalStartupSelfTest();
#else
    this->slotShowPageLogin();
#endif
}

/*
 * Function:    slotSelfTestCompleted
 * Description: Self-test completed
 * Paramer:     int nErrCode - error code
 * Return:      void
 */
void WidgetManager::slotSelfCheckCompleted(int nErrCode)
{
    qDebug() << Q_FUNC_INFO << nErrCode;

    if(0 > nErrCode) {
        FormPromptWidget::getInstance(this)->setPromptInfo(tr("Prompt"), tr("Instrument self-test failed") + QString("[%1]").arg(nErrCode), true, 30 * 1000);
    }

    this->slotShowPageLogin();
}

/*
* Function:		slotShowPageLogin
* Description:	Show the login window
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageLogin()
{
    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmToolBar){
        m_pFrmToolBar->hide();
    }

    if(m_pFrmStatusBar){
        m_pFrmStatusBar->hide();
    }

    if(m_pFrmSelfCheck) {

    }

    if(m_pFrmLogin) {
        m_pFrmLogin->setGeometry(0, 0, DEF_MAINFRAME_WIDTH, DEF_MAINFRAME_HEIGHT);
        m_pFrmLogin->show();

        // Display the login window
        emit m_pFrmLogin->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageHome
* Description:	Show the main window after boot init
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageHome()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmHome){
        m_pFrmHome->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmHome->show();

        // Get login mode & refresh UI
        emit m_pFrmHome->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageSetting
* Description:	Show the setting page after clicked
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageSetting()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmSetting){
        m_pFrmSetting->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmSetting->show();

        // Get login mode & refresh UI
        emit m_pFrmSetting->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageSetMode
* Description:	Show the mode page after clicked menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageSetMode()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmSetMode){
        m_pFrmSetMode->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmSetMode->show();

        // Refresh UI before show the page
        emit m_pFrmSetMode->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageSetLanguage
* Description:	Show the language window after click menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageSetLanguage()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmSetLanguage){
        m_pFrmSetLanguage->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmSetLanguage->show();

        emit m_pFrmSetLanguage->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageSetRTC
* Description:	Show RTC setting window after click menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageSetRTC()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmSetRTC){
        KeyboardMgr::getInstance()->setParent(m_pFrmSetRTC);

        m_pFrmSetRTC->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmSetRTC->show();

        emit m_pFrmSetRTC->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageSetNetwork
* Description:	Show the network page after clicked menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageSetNetwork()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmSetNetwork){
        KeyboardMgr::getInstance()->setParent(m_pFrmSetNetwork);

        m_pFrmSetNetwork->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmSetNetwork->show();

        // Refresh UI before show the page
        emit m_pFrmSetNetwork->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageSetLog
* Description:	Show the log page after clicked menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageSetLog()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmSetLog){
        m_pFrmSetLog->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmSetLog->show();

        // Refresh UI before show the page
        emit m_pFrmSetLog->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageSetUpgrade
* Description:	Show the upgrade setting window after click menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageSetUpgrade()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmSetUpgrade){
        m_pFrmSetUpgrade->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmSetUpgrade->show();
    }
}

/*
* Function:		slotShowPageSetDataTools
* Description:	Show the data tools window after click menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageSetDataTools()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmSetDataTools){
        m_pFrmSetDataTools->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmSetDataTools->show();
    }
}

/*
* Function:		slotShowPageSetVersion
* Description:	Show the version setting window after click menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageSetVersion()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmSetVersion){
        // Refresh UI before show the window
        emit m_pFrmSetVersion->signalRefreshUI();

        m_pFrmSetVersion->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmSetVersion->show();
    }
}

/*
* Function:		slotShowPageResultList
* Description:	Show the result list page after clicked
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageResultList()
{
    qDebug() << Q_FUNC_INFO;
}

/*
* Function:		slotShowPageResultDetails
* Description:	Show the result details page after clicked
* Paramer:		int nTestId - test ID
* Return:		void
*/
void WidgetManager::slotShowPageResultDetails(int nTestId)
{
    qDebug() << Q_FUNC_INFO << nTestId;
}

/*
* Function:		slotShowPageFactory
* Description:	Show the factory page after clicked
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageFactory()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmFactory){
        m_pFrmFactory->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmFactory->show();

        // Get login mode & refresh UI
        emit m_pFrmFactory->signalRefreshUI();
    }
}

/*
 * Function:    slotShowPageUvDisinfection
 * Description: Show the UV disinfection window after click
 * Paramer:     void
 * Return:      int - the error code, 0:success; otherwise: failure
 */
void WidgetManager::slotShowPageUvDisinfection()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmFacUvDisinfection){
        m_pFrmFacUvDisinfection->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmFacUvDisinfection->show();
    }
}

/*
* Function:		slotShowPageHeatingDebug
* Description:	Show the heating debug window after click
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageHeatingDebug()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmFacHeatingDebug){
        m_pFrmFacHeatingDebug->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmFacHeatingDebug->show();

        emit m_pFrmFacHeatingDebug->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageMotorDebug
* Description:	Show the motor debug window after click menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageMotorDebug()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmFacMotorDebug){
        KeyboardMgr::getInstance()->setParent(m_pFrmFacMotorDebug);

        m_pFrmFacMotorDebug->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmFacMotorDebug->show();

        emit m_pFrmFacMotorDebug->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageProcessDebug
* Description:	Show the process debug window after click menus
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageProcessDebug()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmFacProcessDebug){
        KeyboardMgr::getInstance()->setParent(m_pFrmFacProcessDebug);

        m_pFrmFacProcessDebug->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmFacProcessDebug->show();

        // Refresh UI
        emit m_pFrmFacProcessDebug->signalRefreshUI();
    }

}

/*
* Function:		slotShowPagePcrDebug
* Description:	Show the PCR debug window after click menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPagePcrDebug()
{
    qDebug() << Q_FUNC_INFO;
}

/*
 * Function:    slotShowPageExtractDebug
 * Description: Show the extract window after click menu
 * Paramer:     void
 * Return:      void
 */
void WidgetManager::slotShowPageExtractDebug()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmFacExtractDebug){
        m_pFrmFacExtractDebug->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmFacExtractDebug->show();

        // Refresh UI
        emit m_pFrmFacExtractDebug->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageKitList
* Description:	Show the Kit list window after click menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageKitList()
{
    qDebug() << Q_FUNC_INFO;
}

/*
* Function:		slotShowPageFactoryParams
* Description:	Show the factory params setting window after click menu
* Paramer:		int nType - Params type
* Return:		void
*/
void WidgetManager::slotShowPageFactoryParams(int nType)
{
    qDebug() << Q_FUNC_INFO << nType;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmFacFactoryParams){
        KeyboardMgr::getInstance()->setParent(m_pFrmFacFactoryParams);

        m_pFrmFacFactoryParams->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmFacFactoryParams->show();

        // Refresh UI
        emit m_pFrmFacFactoryParams->signalRefreshUI(nType);
    }
}

/*
* Function:		slotShowPageChecking
* Description:	Show the self-checking page after clicked
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageSelfChecking()
{
    qDebug() << Q_FUNC_INFO;

    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmFacSelfChecking) {
        m_pFrmFacSelfChecking->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmFacSelfChecking->show();

        // Refresh UI before show the page
        emit m_pFrmFacSelfChecking->signalRefreshUI();
    }
}

/*
* Function:		slotShowPageDeviceNotify
* Description:	Show the parameter setting window after click menu
* Paramer:		void
* Return:		void
*/
void WidgetManager::slotShowPageDeviceNotify()
{
    // Hide pages & set the geometry for toolbar & statusbar
    _pageHideAndGeometry();

    if(m_pFrmFacDeviceNotify){
        KeyboardMgr::getInstance()->setParent(m_pFrmFacDeviceNotify);

        m_pFrmFacDeviceNotify->setGeometry(0, DEF_TOOL_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_MAIN_WIDGET_HEIGHT);
        m_pFrmFacDeviceNotify->show();
        m_pFrmFacDeviceNotify->signalRefreshUI();
    }
}


/*
* Function:		slotSwitchLanguage
* Description:	Switch the language type
* Paramer:		int eumLangType - the language type
* Return:		void
*/
void WidgetManager::slotSwitchLanguage(int eumLangType)
{
    if(m_pTrans) {
        qApp->removeTranslator(m_pTrans);
        delete m_pTrans;
        m_pTrans = nullptr;
    }
    m_pTrans = new QTranslator();

    QString sLangType = E_LANG_EN_US == eumLangType ? "lang/en_US.qm" : "lang/zh_CN.qm";
    QString sLangFile = QString("%1/%2").arg(qApp->applicationDirPath()).arg(sLangType);

    bool bLoad = m_pTrans->load(sLangFile);
    bool bInstall = qApp->installTranslator(m_pTrans);

    qDebug() << Q_FUNC_INFO << eumLangType << bLoad << bInstall;
}

/*
* Function:	slotRefreshUI
* Description:	Receive a payload data from serialport (error log)
* Paramer:	unsigned int unCanId - CAN ID
*               int nLevel - error level
*               int nCoding - error coding
* Return:	void
*/
void WidgetManager::slotErrorLogPayload(unsigned int unCanId, int nLevel, int nCoding)
{
    qDebug() << Q_FUNC_INFO << unCanId << nLevel << nCoding;

    if(E_ERR_WARNING < nLevel) {
        QString sErrInfo = UtilityAPI::getInstance()->getErrorDescByCodeInspect(nCoding);
        FormPromptWidget::getInstance(this)->setPromptInfo(tr("Error"), sErrInfo, true, 30 * 1000);
    }
}


/*
* Function:		_pageHideAndGeometry
* Description:	Hide pages & set the geometry for toolbar & statusbar
* Paramer:		void
* Return:		void
*/
void WidgetManager::_pageHideAndGeometry()
{
    // Hide all windows firstly
    foreach (QWidget *pWidget, m_lstWidgets) {
        if(pWidget) {
            if(!pWidget->isHidden()) {
                pWidget->hide();
            }
        }
    }

    if(m_pFrmToolBar){
        m_pFrmToolBar->setGeometry(0, 0, DEF_MAINFRAME_WIDTH, DEF_TOOL_BAR_HEIGHT);
        m_pFrmToolBar->show();
    }

    if(m_pFrmStatusBar){
        m_pFrmStatusBar->setGeometry(0, DEF_MAINFRAME_HEIGHT - DEF_STATUS_BAR_HEIGHT, DEF_MAINFRAME_WIDTH, DEF_STATUS_BAR_HEIGHT);
        m_pFrmStatusBar->show();
    }
}

/*
* Function:		_loadCommonQSS
* Description:	Load the QSS file for the common control
* Paramer:		void
* Return:		void
*/
void WidgetManager::_loadCommonQSS()
{
    qDebug() << Q_FUNC_INFO;

    QString sQssData;
    QStringList lstQss;
    lstQss << "QLabel" << "QLineEdit" << "QPushButton" << "QComboBox" << "QRadioButton" << "QCheckBox"
           << "QProgressBar" << "QDateEdit" << "QScrollBar"
           << "QFrame"  << "QTabWidget"<< "QTreeWidget" << "QTableWidget";

    if(0 < lstQss.size()) {
        for(int i=0; i<lstQss.size(); i++) {
            QFile qssFile;
            qssFile.setFileName(QString(":/%1/common/%2.qss").arg("skin_1").arg(lstQss.at(i)));
            if(qssFile.open(QFile::ReadOnly)) {
                sQssData += qssFile.readAll();
                qssFile.close();
            }
        }
        qApp->setStyleSheet(sQssData);
    }

    qDebug() << Q_FUNC_INFO << lstQss.size();
}

/*
 * Function:    _loadPlugins
 * Description: Load plugins from local
 * Paramer:     void
 * Return:      int - 0: success; otherwise: failed
 */
int WidgetManager::_loadPlugins()
{
    qDebug() << Q_FUNC_INFO;

    int nRetVal = -10000;

    m_mapInterface.clear();

    std::map<QString, QString> mapPluginInfo;
    QDir pluginsDir(".");

    QDir dirPlugins("plugins");
    if(!dirPlugins.exists()) {
        nRetVal = -5;
        goto do_exit;
    }

    pluginsDir.cd("plugins");

#if QT_PRO_DEBUG_ON_WINDOWS
#ifdef QT_NO_DEBUG
#ifdef DF_IF_ICOM
    mapPluginInfo[DF_IF_ICOM] = "serialport.dll";
#endif
#ifdef DF_IF_ICAN
    mapPluginInfo[DF_IF_ICAN] = "can.dll";
#endif
#else
#ifdef DF_IF_ICOM
    mapPluginInfo[DF_IF_ICOM] = "serialportd.dll";
#endif
#ifdef DF_IF_ICAN
    mapPluginInfo[DF_IF_ICAN] = "can.dll";
#endif
#endif
#else
#ifdef DF_IF_ILOG
    mapPluginInfo[DF_IF_ILOG] = "liblog4qt.so";
#endif

#ifdef DF_IF_ICOM
    mapPluginInfo[DF_IF_ICOM] = "libserialport.so";
#endif

#ifdef DF_IF_ICAN
    mapPluginInfo[DF_IF_ICAN] = "libcan.so";
#endif
#endif

    foreach (const auto &iter, mapPluginInfo) {
        QString sInterface = iter.first;
        QString sFileName = iter.second;
        qDebug() << Q_FUNC_INFO << sInterface << sFileName << pluginsDir.absoluteFilePath(sFileName);

        QPluginLoader *pPlgLoader = new QPluginLoader(pluginsDir.absoluteFilePath(sFileName));
        if(pPlgLoader) {
            pPlgLoader->load();

            if(pPlgLoader->isLoaded()) {
                QObject *pPlugin = pPlgLoader->instance();
                if (pPlugin) {
                    std::map<QString, QPluginLoader*>::iterator iterEx = g_mapPluginLoader.find(sInterface);
                    if(g_mapPluginLoader.end() == iterEx) {
                        g_mapPluginLoader.insert(std::pair<QString, QPluginLoader*>(sInterface, pPlgLoader));
#ifdef DF_IF_ILOG
                        if(DF_IF_ILOG == sInterface) {
                            ILog4Qt *pILog = qobject_cast<ILog4Qt *>(pPlugin);
                            m_mapInterface.insert(std::pair<QString, QObject*>(sInterface, pILog));
                        }
#endif

#ifdef DF_IF_ICOM
                        if(DF_IF_ICOM == sInterface) {
                            ISerialport *pISerialport = qobject_cast<ISerialport *>(pPlugin);
                            m_mapInterface.insert(std::pair<QString, QObject*>(sInterface, pISerialport));
                        }
#endif

#ifdef DF_IF_ICAN
                        if(DF_IF_ICAN == sInterface) {
                            ICan *pICan = qobject_cast<ICan *>(pPlugin);
                            m_mapInterface.insert(std::pair<QString, QObject*>(sInterface, pICan));
                        }
#endif
                    }
                    else {
                        nRetVal = -3;
                        goto do_exit;
                    }
                }
            }
            else {
                qDebug() << Q_FUNC_INFO << pPlgLoader->errorString();

                nRetVal = -2;
                goto do_exit;
            }
        }
        else {
            nRetVal = -1;
            goto do_exit;
        }
    }

    if(0 < g_mapPluginLoader.size()) {
        nRetVal = g_mapPluginLoader.size();
    }

do_exit:
    qDebug() << Q_FUNC_INFO << nRetVal;
    return nRetVal;
}

/*
 * Function:    _unloadPlugins
 * Description: Unload plugins
 * Paramer:     void
 * Return:      int - 0: success; otherwise: failed
 */
void WidgetManager::_unloadPlugins()
{
    qDebug() << Q_FUNC_INFO;

    QStringList lstInterfaces;

#ifdef DF_IF_ILOG
    lstInterfaces << DF_IF_ILOG;
#endif

#ifdef DF_IF_ICOM
    lstInterfaces << DF_IF_ICOM;
#endif

#ifdef DF_IF_ICAN
    lstInterfaces << DF_IF_ICAN;
#endif


    if(lstInterfaces.size() <= (int)g_mapPluginLoader.size()) {
        for(int i=0; i<lstInterfaces.size(); i++) {
            std::map<QString, QPluginLoader*>::iterator iter = g_mapPluginLoader.find(lstInterfaces.at(i));

            qDebug() << Q_FUNC_INFO << iter->first;
#ifdef DF_IF_ILOG
            if(DF_IF_ILOG == iter->first) {
                m_mapInterface.erase(iter->first);
            }
#endif

#ifdef DF_IF_ICOM
            if(DF_IF_ICOM == iter->first) {
                m_mapInterface.erase(iter->first);
            }
#endif

#ifdef DF_IF_ICAN
            if(DF_IF_ICAN == iter->first) {
                m_mapInterface.erase(iter->first);
            }
#endif

            if(iter->second) {
                qDebug() << Q_FUNC_INFO << i << iter->second->fileName();

                if(iter->second->isLoaded()) {
                    if(!iter->second->unload()) {
                        qDebug() << Q_FUNC_INFO << iter->second->errorString();
                    }

                    iter->second->deleteLater();
                    iter->second = nullptr;
                }
            }
            g_mapPluginLoader.erase(iter);
        }
    }

    m_mapInterface.clear();
}

/*
 * Function:    _initPlugins
 * Description: Initialize interfaces
 * Paramer:     void
 * Return:      int - 0: success; otherwise: failed
 */
int WidgetManager::_initInterfaces()
{
    qDebug() << Q_FUNC_INFO;

    int nRetVal = 0;

    // Installs a Qt message handler for prints out debug messages (warnings, critical and fatal error)
#ifdef DF_IF_ILOG
    std::map<QString, QObject*>::iterator iter = m_mapInterface.find(DF_IF_ILOG);
    if(m_mapInterface.end() != iter) {
        Q_ASSERT((ILog4Qt *)(iter->second));

        // Pass the serial port class pointer to the service class
        LogBLL::getInstance(this)->setILog(((ILog4Qt *)(iter->second)));

        qInstallMessageHandler(myMessageHandler);
    }
#endif

#ifdef DF_IF_ICOM
    std::map<QString, QObject*>::iterator iter2 = m_mapInterface.find(DF_IF_ICOM);
    if(m_mapInterface.end() != iter2) {
        // Open COM
        nRetVal = ((ISerialport *)(iter2->second))->openSerialport();
        if(0 != nRetVal) {
            nRetVal = -1;
        }

        // Pass the serial port class pointer to the service class
        SerialportBLL_T3::getInstance(this)->setISerialport(((ISerialport *)(iter2->second)));
    }
#endif

#ifdef DF_IF_ICAN
    std::map<QString, QObject*>::iterator iter3 = m_mapInterface.find(DF_IF_ICAN);
    if(m_mapInterface.end() != iter3) {
        // Open CAN
        nRetVal = ((ICan *)(iter3->second))->openCAN();
        if(0 != nRetVal) {
            nRetVal = -1;
        }

        // Pass the serial port class pointer to the service class
        CanBLL_T1C::getInstance(this)->setICan(((ICan *)(iter3->second)));
    }
#endif

    qDebug() << Q_FUNC_INFO << nRetVal;
    return nRetVal;
}

/*
 * Function:    _uninitPlugins
 * Description: Uninitialize interfaces
 * Paramer:     void
 * Return:      void
 */
void WidgetManager::_uninitInterfaces()
{
    qDebug() << Q_FUNC_INFO;

#ifdef DF_IF_ILOG
    std::map<QString, QObject*>::iterator iter3 = m_mapInterface.find(DF_IF_ILOG);
    if(m_mapInterface.end() != iter3) {
        qInstallMessageHandler(nullptr);

        // Log class pointer is empty
        LogBLL::getInstance(this)->setILog(nullptr);
    }
#endif

#ifdef DF_IF_ICOM
    std::map<QString, QObject*>::iterator iter = m_mapInterface.find(DF_IF_ICOM);
    if(m_mapInterface.end() != iter) {
        // Close COM
        ((ISerialport *)(iter->second))->closeSerialport();

        // Serial port class pointer is empty
        SerialportBLL_T3::getInstance(this)->setISerialport(nullptr);
    }
#endif

#ifdef DF_IF_ICAN
    std::map<QString, QObject*>::iterator iter2 = m_mapInterface.find(DF_IF_ICAN);
    if(m_mapInterface.end() != iter2) {
        // Close CAN
        ((ICan *)(iter2->second))->closeCAN();

        // Can class pointer is empty
        CanBLL_T1C::getInstance(this)->setICan(nullptr);
    }
#endif
}

/*
* Function:		_switchLanguage
* Description:	Switch the language(English/Chinese)
* Paramer:		bool bEnglish - set english as default language
* Return:		void
*/
void WidgetManager::_switchLanguage(bool bEnglish)
{
    if(m_pTrans) {
        qApp->removeTranslator(m_pTrans);
        delete m_pTrans;
        m_pTrans = nullptr;
    }
    m_pTrans = new QTranslator();

    bool bLoad = m_pTrans->load(bEnglish ? "./lang/en_US.qm" : "./lang/zh_CN.qm");
    bool bInstall = qApp->installTranslator(m_pTrans);

    qDebug() << Q_FUNC_INFO << bEnglish << bLoad << bInstall;
}

/*
 * Function:    _configFromINI
 * Description: Configure language & CAN
 * Paramer:     void
 * Return:      void
 */
void WidgetManager::_configFromINI()
{
    // Get the language type & refresh the UI language
    ST_CFG_LANGUAGE stLangType;
    ConfigureBLL::getInstance(this)->loadLanguageType(stLangType);
    this->slotSwitchLanguage(stLangType.eumLangType);

    qDebug() << Q_FUNC_INFO << stLangType.eumLangType << CanVars::gs_nIapCanID_CH1 << CanVars::gs_nPcrCanID_CH1;
}

/*
 * Function:    _configFirmware
 * Description: Config firmware
 * Paramer:     void
 * Return:      void
 */
void WidgetManager::_configFirmware()
{
}

/*
 * Function:    _getWindowInstance
 * Description: et the window instances
 * Paramer:     void
 * Return:      void
 */
void WidgetManager::_getWindowInstance()
{
    // The home windows
    if(!m_pFrmStatusBar) m_pFrmStatusBar = FormStatusBar::getInstance(this);
    if(!m_pFrmToolBar) m_pFrmToolBar = FormToolBar::getInstance(this);
    if(!m_pFrmHome) m_pFrmHome = FormHome::getInstance(this);
    Q_ASSERT(m_pFrmStatusBar && m_pFrmToolBar && m_pFrmHome);
    m_lstWidgets << m_pFrmStatusBar << m_pFrmToolBar << m_pFrmHome;

    if(!m_pFrmSelfCheck) m_pFrmSelfCheck = FormSelfCheck::getInstance(this);
    if(!m_pFrmLogin) m_pFrmLogin = FormLogin::getInstance(this);
    Q_ASSERT(m_pFrmSelfCheck && m_pFrmLogin);
    m_lstWidgets << m_pFrmSelfCheck << m_pFrmLogin;

    // The setting pages
    if(!m_pFrmSetting) m_pFrmSetting = FormSetting::getInstance(this);
    if(!m_pFrmSetMode) m_pFrmSetMode = FormSettingMode::getInstance(this);
    if(!m_pFrmSetRTC) m_pFrmSetRTC = FormSettingRTC::getInstance(this);
    if(!m_pFrmSetLanguage) m_pFrmSetLanguage = FormSettingLanguage::getInstance(this);
    if(!m_pFrmSetNetwork) m_pFrmSetNetwork = FormSettingNetwork::getInstance(this);
    if(!m_pFrmSetLog) m_pFrmSetLog = FormSettingLog::getInstance(this);
    if(!m_pFrmSetUpgrade) m_pFrmSetUpgrade = FormSettingUpgrade::getInstance(this);
    if(!m_pFrmSetDataTools) m_pFrmSetDataTools = FormSettingDataTools::getInstance(this);
    if(!m_pFrmSetVersion) m_pFrmSetVersion = FormSettingVersion::getInstance(this);

    Q_ASSERT(m_pFrmSetting && m_pFrmSetMode && m_pFrmSetLanguage && m_pFrmSetRTC && m_pFrmSetNetwork && m_pFrmSetLog && m_pFrmSetUpgrade && m_pFrmSetDataTools && m_pFrmSetVersion);
    m_lstWidgets << m_pFrmSetting << m_pFrmSetMode << m_pFrmSetLanguage << m_pFrmSetRTC << m_pFrmSetNetwork << m_pFrmSetLog << m_pFrmSetUpgrade << m_pFrmSetDataTools << m_pFrmSetVersion;

    // The factory pages
    if(!m_pFrmFactory) m_pFrmFactory = FormFactory::getInstance(this);
    if(!m_pFrmFacProcessDebug) m_pFrmFacProcessDebug = FormProcessDebug::getInstance(this);
    if(!m_pFrmFacMotorDebug) m_pFrmFacMotorDebug = FormMotorDebug::getInstance(this);
    if(!m_pFrmFacHeatingDebug) m_pFrmFacHeatingDebug = FormHeatingDebug::getInstance(this);
    if(!m_pFrmFacExtractDebug) m_pFrmFacExtractDebug = FormExtractDebug::getInstance(this);
    if(!m_pFrmFacUvDisinfection) m_pFrmFacUvDisinfection = FormUvDisinfection::getInstance(this);
    if(!m_pFrmFacFactoryParams) m_pFrmFacFactoryParams = FormFactoryParams::getInstance(this);
    if(!m_pFrmFacSelfChecking) m_pFrmFacSelfChecking = FormSelfChecking::getInstance(this);
    if(!m_pFrmFacDeviceNotify) m_pFrmFacDeviceNotify = FormDeviceNotify::getInstance(this);
    Q_ASSERT(m_pFrmFactory && m_pFrmFacHeatingDebug && m_pFrmFacMotorDebug && m_pFrmFacProcessDebug && m_pFrmFacUvDisinfection && m_pFrmFacExtractDebug && m_pFrmFacFactoryParams && m_pFrmFacSelfChecking && m_pFrmFacDeviceNotify);
    m_lstWidgets << m_pFrmFactory << m_pFrmFacHeatingDebug << m_pFrmFacMotorDebug << m_pFrmFacProcessDebug << m_pFrmFacUvDisinfection << m_pFrmFacExtractDebug << m_pFrmFacFactoryParams << m_pFrmFacSelfChecking << m_pFrmFacDeviceNotify;

    qDebug() << Q_FUNC_INFO << m_lstWidgets.size();
}

/*
 * Function:    _associateSignalSlot
 * Description: Correlation signal and slot function
 * Paramer:     void
 * Return:      void
 */
void WidgetManager::_associateSignalSlot()
{
    // Signal-slot initialization
    std::vector<bool> vecConnect;

    vecConnect.push_back(QObject::connect(CanBLL_T1C::getInstance(this), SIGNAL(signalErrorLogPayload(unsigned int, int, int)), this, SLOT(slotErrorLogPayload(unsigned int, int, int)), static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection)));

    vecConnect.push_back(QObject::connect(m_pFrmSelfCheck, SIGNAL(signalSelfCheckCompleted(int)), this, SLOT(slotSelfCheckCompleted(int)), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));

    vecConnect.push_back(QObject::connect(m_pFrmLogin, SIGNAL(signalFinishLogin()), this, SLOT(slotShowPageHome()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmLogin, SIGNAL(signalRefreshLoginMode(int)), m_pFrmStatusBar, SLOT(slotRefreshLoginMode(int)), Qt::QueuedConnection));

    vecConnect.push_back(QObject::connect(m_pFrmToolBar, SIGNAL(signalShowPageHome()), this, SLOT(slotShowPageHome()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmToolBar, SIGNAL(signalShowPageSetting()), this, SLOT(slotShowPageSetting()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmToolBar, SIGNAL(signalShowPageResult()), this, SLOT(slotShowPageResultList()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmToolBar, SIGNAL(signalShowPageFactory()), this, SLOT(slotShowPageFactory()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));

    vecConnect.push_back(QObject::connect(m_pFrmSetting, SIGNAL(signalShowPageMode()), this, SLOT(slotShowPageSetMode()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmSetting, SIGNAL(signalShowPageLanguage()), this, SLOT(slotShowPageSetLanguage()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmSetting, SIGNAL(signalShowPageDatetime()), this, SLOT(slotShowPageSetRTC()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmSetting, SIGNAL(signalShowPageNetwork()), this, SLOT(slotShowPageSetNetwork()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmSetting, SIGNAL(signalShowPageLog()), this, SLOT(slotShowPageSetLog()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmSetting, SIGNAL(signalShowPageUpgrade()), this, SLOT(slotShowPageSetUpgrade()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmSetting, SIGNAL(signalShowPageDataTools()), this, SLOT(slotShowPageSetDataTools()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmSetting, SIGNAL(signalShowPageVersion()), this, SLOT(slotShowPageSetVersion()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));

    vecConnect.push_back(QObject::connect(m_pFrmFactory, SIGNAL(signalShowPageProcessDebug()), this, SLOT(slotShowPageProcessDebug()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmFactory, SIGNAL(signalShowPagePcrDebug()), this, SLOT(slotShowPagePcrDebug()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmFactory, SIGNAL(signalShowPageKitManage()), this, SLOT(slotShowPageKitList()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmFactory, SIGNAL(signalShowPageMotorDebug()), this, SLOT(slotShowPageMotorDebug()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmFactory, SIGNAL(signalShowPageHeatingDebug()), this, SLOT(slotShowPageHeatingDebug()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmFactory, SIGNAL(signalShowPageExtractDebug()), this, SLOT(slotShowPageExtractDebug()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmFactory, SIGNAL(signalShowPageUvDisinfection()), this, SLOT(slotShowPageUvDisinfection()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmFactory, SIGNAL(signalShowPageFactoryParams(int)), this, SLOT(slotShowPageFactoryParams(int)), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmFactory, SIGNAL(signalShowPageSelfChecking()), this, SLOT(slotShowPageSelfChecking()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmFactory, SIGNAL(signalShowPageDeviceNotify()), this, SLOT(slotShowPageDeviceNotify()), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));

    vecConnect.push_back(QObject::connect(m_pFrmSetLanguage, SIGNAL(signalSwitchLanguage(int)), this, SLOT(slotSwitchLanguage(int)), static_cast<Qt::ConnectionType>(Qt::AutoConnection | Qt::UniqueConnection)));
    vecConnect.push_back(QObject::connect(m_pFrmSetMode, SIGNAL(signalRefreshLoginMode(int)), m_pFrmStatusBar, SLOT(slotRefreshLoginMode(int)), Qt::QueuedConnection));

    for(int i=0; i<(int)vecConnect.size(); i++) {
        Q_ASSERT(vecConnect.at(i));
    }

    qDebug() << Q_FUNC_INFO << vecConnect.size();
}
